Skip to content

Conversation

@burhankhaja
Copy link

Problem
Pinocchio lacks the support for Token2022 extensions.

Solution
Added full Token2022 extension support, including instruction handlers and logic for complete functionality. All tests pass, confirming compatibility with the Token2022 standard.

@burhankhaja
Copy link
Author

burhankhaja commented Oct 27, 2025

Pending Extensions

  • Token Metadata
  • Transfer Fee
  • Confidential Extensions

/// Return a `TransferHook` from the given bytes (unsafe, unchecked).
#[inline(always)]
pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
&*(bytes[Self::AUTHORITY_START as usize..].as_ptr() as *const TransferHook)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit strange to use a fix offset to where the extension will start since it depends on what other extensions are enabled. This is why the original token-2022 code looks up where the extension data is: https://github.com/solana-program/token-2022/blob/main/interface/src/extension/mod.rs#L148-L183

}

#[inline(always)]
pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no signers on this instruction, so we should only have invoke.

/// Mint Account to initialize.
pub mint_account: &'a AccountInfo,
/// Optional authority that can set the transfer hook program id
pub authority: Option<&'a Pubkey>,
Copy link
Collaborator

@febo febo Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use a different lifetime than AccountInfo references. This applies to all Pubkey values.

Suggested change
pub authority: Option<&'a Pubkey>,
pub authority: Option<&'b Pubkey>,

ProgramResult,
};

pub struct InitializeTransferHook<'a> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub struct InitializeTransferHook<'a> {
pub struct InitializeTransferHook<'a, 'b> {

@@ -0,0 +1,215 @@
# Pinocchio Interface Test Setup for SPL Token-2022
Copy link
Collaborator

@febo febo Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cpi-tests should under the token-2022 folder since it is specific to it.

/// The length of the account with `CpiGuard` extension data
const LEN: u8 = 171;
/// The index where CPI guard data starts in the account with `CpiGuard` extension data
const CPI_GUARD_START: u8 = 170;
Copy link
Collaborator

@febo febo Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't assume a fixed position for the start of the extension data.

@febo
Copy link
Collaborator

febo commented Oct 30, 2025

Thanks for your contribution - it is a good start. Left a few comments that apply to the majority of the extensions. In general:

  • Instructions that do not expect signers do not need an invoke_signer.
  • We cannot have fixed offset for extension state – it all depends on which extensions are enabled on the account.
  • Lifetime of values on the instruction builders need revision – values that can come from a different source (e.g., AccountInfo and Pubkey) should have different lifetimes.

The PR is also quite big so I suggest breaking it in smaller ones. Start adding the instruction builder for each extension under src/instructions/extensions. The state is a bit more complicated and should be on its own PR – see #225.

@burhankhaja
Copy link
Author

burhankhaja commented Oct 30, 2025

Thanks for the detailed feedback, Febo. The point about fixed offsets makes complete sense, that is a real issue on our end, we will make sure to address it in our upcoming pull requests.

We will also address the other recommendations accordingly, separating lifetimes, removing unnecessary invoke_signers, adding extensions under src/instructions/extensions, and moving cpi-tests under token-2022

Just to confirm, when we split the extensions into separate PRs, should each extension include its own tests within the same PR, or should we submit the tests in separate PRs afterward?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants